#include "material/gameobjectmaterial.h"


CGameObjectMaterial::CGameObjectMaterial() :
CMaterial() {
    m_hParameEnableHandle = -1;
    m_hFlagColorHandle = -1;
    strcpy( m_strName, "GameObjectMaterial" );
}
CGameObjectMaterial::~CGameObjectMaterial() {

}
void CGameObjectMaterial::Init() {
    CMaterial::Init();

    const char* _strVertexShader = "\
/*#ifdef __HIGHTP__*/ \n\
    precision highp float; \n\
/*#endif*/ \n\
uniform mat4 projectionMatrix;\
uniform mat4 viewMatrix;\
uniform mat4 modelMatrix;\
uniform mat3 normalMatrix;\
uniform vec3 lightDirection;\
uniform float billboardType;\
uniform mat4 boneMatrices[250];\
attribute vec3 a_position;\
attribute vec3 a_normal0; \
attribute vec2 a_texcoord0;\
attribute vec4 a_skinIndex;\
attribute vec4 a_skinWeight;\
varying vec3 vNormal;\
varying vec3 vLightDir;\
varying vec2 vUv0;\
varying float fogDepth;\n\
mat4 getBoneMatrix( const in float i ){\
    mat4 bone = boneMatrices[int( i )];\
    return bone;\
}\
void main(){\
mat4 rotationMatrix = mat4(\
    1.0, 0.0, 0.0,0.0,\
    0.0, 5.96046448e-08, -0.999999940,0.0,\
    0.0, 0.999999940, 5.96046448e-08,0.0,\
    0.0, 0.0, 0.0,1.0\
);\
vec4 objectNormal = vec4( a_normal0, 0.0 );\
vec4 transformed = vec4( a_position, 1.0 );\
mat4 boneMatX = getBoneMatrix( a_skinIndex.x ); \
mat4 boneMatY = getBoneMatrix( a_skinIndex.y ); \
mat4 boneMatZ = getBoneMatrix( a_skinIndex.z ); \
mat4 boneMatW = getBoneMatrix( a_skinIndex.w ); \
mat4 skinMatrix = mat4( 0.0 );\
skinMatrix += a_skinWeight.x * boneMatX;\
skinMatrix += a_skinWeight.y * boneMatY;\
skinMatrix += a_skinWeight.z * boneMatZ;\
skinMatrix += a_skinWeight.w * boneMatW;\
objectNormal =  skinMatrix * objectNormal;\
vNormal = normalize( normalMatrix * objectNormal.xyz );\
vec4 mvPosition = viewMatrix * skinMatrix * transformed;\
vLightDir = normalize( vec3( (viewMatrix * vec4((lightDirection * 100000.0),1.0))) );\
fogDepth = -mvPosition.z; \
gl_Position = projectionMatrix * mvPosition;\
vUv0 = a_texcoord0;\
}";

    const char* _strFragmentShader =
        "                                \
/*#ifdef __HIGHTP__*/ \n\
    precision highp float; \n\
/*#endif*/ \n\
uniform sampler2D diffuseMap; \n\
uniform vec3 lightColor;\n\
uniform vec4 fogEnable;\n\
uniform vec4 fogColor;\n\
uniform vec4 fogInfo;\n\
uniform vec4 paramEnable;\n\
uniform vec4 flagColor;\n\
uniform vec3 textureUVOffset;\n\
uniform vec4 meshColor;\n\
varying vec3 vNormal;\n\
varying vec3 vLightDir;\n\
varying vec2 vUv0;\n\
varying float fogDepth;\n\
vec4 ads(){\n\
    vec3 _vLightColor = lightColor * dot(vNormal, vLightDir);\n\
    return vec4( max(_vLightColor, lightColor * 0.285 ), 1.0 );\n\
}\n\
void main(){\n\
    vec4 _color0 = flagColor;\n\
    vec2 _vUVs = vUv0 + textureUVOffset.xy;\n\
    vec4 _color1 = texture2D(diffuseMap, _vUVs );\n\
    vec4 texelColor;\n\
    if( paramEnable.x == 0 )\n\
        texelColor = _color1;\n\
    else\n\
        texelColor = mix( _color0, _color1, _color1.a );\n\
    texelColor *= meshColor;\n\
    if( texelColor.a < 0.01 )discard;\n\
    if( paramEnable.y == 0 )\n\
        gl_FragColor = texelColor * 1.0;\n\
    else\n\
        gl_FragColor = texelColor * ads() * 1.0;\n\
    float fogFactor = smoothstep( fogInfo.x, fogInfo.y, fogDepth );\n\
    gl_FragColor.rgb = mix( gl_FragColor.rgb, fogColor.rgb, fogFactor );\n\
}";

    m_hMaterialHandle = Material_Create(m_strName, (byte*)_strVertexShader, strlen(_strVertexShader), (byte*)_strFragmentShader, strlen(_strFragmentShader));
    m_hProjectionMatrixHandle = Material_GetUniform(m_hMaterialHandle, "projectionMatrix", EUT_MATRIX44);
    m_hViewMatrixHandle = Material_GetUniform(m_hMaterialHandle, "viewMatrix", EUT_MATRIX44);
    m_hModelMatrixHandle = Material_GetUniform(m_hMaterialHandle, "modelMatrix", EUT_MATRIX44);
    m_hNormalMatrixHandle = Material_GetUniform(m_hMaterialHandle, "normalMatrix", EUT_MATRIX33);
    m_hBoneMatricesHandle = Material_GetUniform(m_hMaterialHandle, "boneMatrices", EUT_MATRIX44 );
    //m_hDiffuseHandle = Material_GetUniform(m_hMaterialHandle, "diffuse", EUT_VEC4);
    m_hDirectionalLights_0_directionHandle = Material_GetUniform(m_hMaterialHandle, "lightDirection", EUT_VEC3);
    m_hDirectionalLights_0_colorHandle = Material_GetUniform(m_hMaterialHandle, "lightColor", EUT_VEC3);
    

    m_hLightEnableHandle = Material_GetUniform(m_hMaterialHandle, "lightEnable", EUT_VEC4 );
    m_hFogColorHandle = Material_GetUniform(m_hMaterialHandle, "fogColor", EUT_VEC4);
    m_hFogInfoHandle = Material_GetUniform(m_hMaterialHandle, "fogInfo", EUT_VEC4);
    m_hDiffuseMapHandle = Material_GetUniform(m_hMaterialHandle, "diffuseMap", EUT_SAMPLER);
    m_hTextureUVOffsetHandle = Material_GetUniform(m_hMaterialHandle, "textureUVOffset", EUT_VEC3 );

    m_hParameEnableHandle = Material_GetUniform( m_hMaterialHandle, "paramEnable", EUT_VEC4 );
    m_hFlagColorHandle = Material_GetUniform( m_hMaterialHandle, "flagColor", EUT_VEC4 );
    m_hMeshColorHandle = Material_GetUniform( m_hMaterialHandle, "meshColor", EUT_VEC4 );
    
}

void CGameObjectMaterial::SetParameEnable( bool32 b0, bool32 b1, bool32 b2, bool32 b3 ){
    float _vValue[4] = { 0 };
    _vValue[0] = b0;
    _vValue[1] = b1;
    _vValue[2] = b2;
    _vValue[3] = b3;
    SetUniform4fv( m_hParameEnableHandle, _vValue );
}
void CGameObjectMaterial::SetFlagColor( Color c ){
    SetUniform4fv( m_hFlagColorHandle, c );
}
void CGameObjectMaterial::SetTextureUVOffset( Vector3 pUVs ){
    SetUniform3fv( m_hTextureUVOffsetHandle, pUVs );
}
void CGameObjectMaterial::SetMeshColor( Color c ){
    SetUniform4fv( m_hMeshColorHandle, c );
}
void CGameObjectMaterial::SetUserParameValue( uint32 nName, int32 nDataType, void* pData ){
    float* _pData = (float*)pData;
    switch( nName ){
    case 0:{ 
        SetParameEnable( _pData[0], _pData[1], _pData[2], _pData[3] );
    }break;
    case 1:{
        SetFlagColor( _pData );
    }break;
    case 2:{
        SetTextureUVOffset( _pData );
    }break;
    case 3:{
        SetMeshColor( _pData);
    }break;
    }
}

